<?php
class CommonUtils {
	
    ////////////////////////////////////////////////////////////////////////////////
    //                                  CONSTANTS                                 //
    ////////////////////////////////////////////////////////////////////////////////

    /**
     * Maintain state with GET-mode formatting.
     * @see state
     */
    const state_mod_get = 'GET';

    /**
     * Maintain state with POST-mode formatting.
     * @see state
     */
    const state_mod_post= 'POST';


    /**
     * Set minmal year for input value. 
     */
    const minYear  = 1970;

    ////////////////////////////////////////////////////////////////////////////////
    //                              STRING FUNCTIONS                              //
    ////////////////////////////////////////////////////////////////////////////////


    /**
     * Converts spaces to &nbsp; entities.
     *
     * @param  string $_str String to be converted.
     * @return string       String which has been converted.
     */
    public static function sp2nb( $_str ) {
        return str_replace( " ", "&nbsp;", $_str );
    }

    /**
     * Makes a string's first character lowercase. Does the opposite of ucfirst.
     *
     * @param  string $_str String to be converted.
     * @return string       String which has been converted.
     */
    public static function lcfirst( $_str ) {
        return strtolower( substr( $_str, 0, 1  ) ).substr( $_str, 1 );
    }

    /**
     * Returns the "s" character which appears on the end of plural numbers. Will
     * return an empty string if no plural is required (i.e. the input was 1).
     *
     * @param  int    $_int The integer which may or may not need pluralising.
     * @return string       Either "s" or "" depending on whether $_int is 1.
     */
    public static function plural( $_int ) {
        return ( $_int == 1 ) ? "" : "s";
    }

    /**
     * Returns the number of words in a string. Words are counted in a fairly
     * primitive but 'good enough' manner.
     *
     * @param  string $str String to be counted.
     * @return int         Number of words in the string.
     */
    public static function wordCount( $_str ) {
        return sizeof( explode( " ", strip_tags( $_str ) ) );
    }


    ////////////////////////////////////////////////////////////////////////////////
    //                          DATE AND TIME FUNCTIONS                           //
    ////////////////////////////////////////////////////////////////////////////////


    /**
     * Returns a float value of the current Unix timestamp with milliseconds,
     * from the output of microtime().
     *
     * @return float Value of seconds plus millis.
     */
    public static function getMicrotime() {
        list( $millis, $seconds ) = explode( " ", microtime() );
        return ( (float)$millis + (float)$seconds );
    }

    /**
     * Returns the number of days since the epoch.
     *
     * @param  int $_date Unix timestamp of the date.
     * @return int        Day number of the date.
     */
    public static function dayNumber( $_date ) {
        return floor( $_date / 86400 );
    }

    /**
     * Returns the weekday of a date, according to date("w").
     *
     * @param  int    $_date Unix timestamp of the date.
     * @return string        Weekday number of the date.
     */
    public static function weekday($date) {
        $dateArr = explode("-", $date);
    }
	
	/**
	 * Check if input date is a valid date.
	 *
	 * @param string $date Input value. 
	 * @return bool  If input date is a valid date format, return true otherwise return false.
	 */
    public static function checkDate($date) { 
        $dateArr = explode("-", $date);
        if (is_numeric($dateArr[0]) && is_numeric($dateArr[1]) && is_numeric($dateArr[2])) {
            return checkdate($dateArr[1],$dateArr[2],$dateArr[0]);
        }
        return false;
    } 
	
   /**
	* Check if input time is in a valid time format.
	*
	* @param string $time Input time.
	*
	* @return bool Return true if time is in valid format, otherwise return false.
	*/
	public static function checkTime($time) { 
		$timeArr = explode(":", $time);
		if (is_numeric($timeArr[0]) && is_numeric($timeArr[1]) && is_numeric($timeArr[2])) { //开源代码myokweb.cn
			if (($timeArr[0] >= 0 && $timeArr[0] <= 23) 
			&& ($timeArr[1] >= 0 && $timeArr[1] <= 59) && ($timeArr[2] >= 0 && $timeArr[2] <= 59)) {
				return true;
			}
			else {
				return false;
			}
		}

		return false;
	} 

	/**
	 * Calculate finiacial year based on an given year and month value.
	 * For instance , if year = 2010 and month = 11, at this month, it will belong to 
	 * finacial year 2011, so the function will return 2011.
	 *
	 * @param string $year Input year for example "2011"
	 * @param string $month Input month value for example "5" is for May.
	 *
	 * @return string 
	 */
    public static function getFinancialYear($year, $month) {
        $returnValue = false;
        if(is_int($year) and is_int($month)) {
            if( ($month > 0 and $month <= 12) and ($year > self::minYear and $year <= (date('Y') + 1)) ) {
                if($month > 6) {
                    $returnValue = $year + 1;
                } else {
                    $returnValue = $year;
                }
            }
        } 

        return $returnValue;
    }
	
	/**
	 * Convert month number to name.
	 *
	 * @param int $monthNumber Number of month. 
	 *
	 * @return string Name of month.
	 */
    public static function monthNumberToName($monthNumber) {
        $timestamp = mktime(0, 0, 0, $monthNumber, 1);
        $monthName = date('M',  $timestamp);
        return $monthName;
    }
	
	/**
	 * Rearrange months by an given financial year, for instance if the input year is 2011, this function will return
	 * an array((2010,7),(2010,8),(2010,9),(2010,10),,,,(2011,6))
	 *
	 * @param string $year Input year value.
	 *
	 * @return array Array with correct order of all months in an given financial year.
	 */
    public static function rearrangeMonthsByFYear($year) {
        if($year == null or $year == "") {
            return false;
        }

        $year = (int)$year;

        $returnArray = array(array($year-1, 7),
                array($year-1, 8),
                array($year-1, 9),
                array($year-1, 10),
                array($year-1, 11),
                array($year-1, 12),
                array($year, 1),
                array($year, 2),
                array($year, 3),
                array($year, 4),
                array($year, 5),
                array($year, 6),
                );
        return $returnArray;
    }

    /**
     * Calculate difference in dates
     *
     * @param String(date) $sStartDate
     * @param String(date) $sFinalDate
	 * 
     * @return Integer
     */
    public static function dateDiff($sStartDate, $sFinalDate){
        $sDateI = explode("-", $sStartDate);
        $sDateF = explode("-", $sFinalDate);

        $nStartDate = mktime(0, 0, 0, $sDateI[1], $sDateI[0], $sDateI[2]);
        $nFinalDate = mktime(0, 0, 0, $sDateF[1], $sDateF[0], $sDateF[2]);

        return ($nStartDate > $nFinalDate) ? floor(($nStartDate - $nFinalDate)/86400) : floor(($nFinalDate - $nStartDate)/86400);
    }

    /**
     * Calculate age
     * The entry is the date of birth
     * Format: dd-mm-aaaa
     * 
     * @param String(date) $dtBorn
	 *
     * @return Integer
     */
    public static function calculateAge($dtBorn){
        $date1 		= str_replace("/" ,"-",$dtBorn);
        $date2 		= date("d-m-Y"); // Today

        $result  	= $this->datediff("$date1", "$date2");
        $years		= $result/365;
        $age		= explode("." , $years);
        return  $age[0];
    }

    /**
     * Days that have in month
     *
     * @return Integer
     */
    public static function daysActualMonth(){
        $actual_month = date("m", time());
        $actual_year  = date("Y", time());
        return cal_days_in_month(CAL_GREGORIAN, $actual_month, $actual_year);
    }

    /**
     * Formats data coming from the database in the format YYYY-mm-dd hh:mm:ss
     *
     * @param String(date) $dataBD
     * @param Integer $act
     * @return unknown
     */
    public static function formatDateTime($dataBD,$act=1){
        list($date,$time)  	  		   = explode(" ",$dataBD);
        list($ano, $mes,$dia) 		   = explode("-",$date);
        list($hora, $minuto,$segundo)  = explode(":",$time);

        $retorno = "";
        switch ($act) {
            default:
            case 1: //Date on the Brazilian format: dd/mm/yyyy
                $return = $dia."/".$mes."/".$ano;
                break;
            case 2: // Time on the Brazilian format: hh:mm:ss
                $return = $hora.":".$minuto.":".$segundo;
                break;
            case 3: // Data on the North American format: mm/dd/yyyy
                $return = $mes."/".$dia."/".$ano;
                break;
        }
        return $return;
    }

    /**
     * Return the current day
     *
     * @param String $lng
     * @return String
     */
    public static function currentDay($lng = "pt"){ // Paramter can be pt or en
        $day = getdate();
        $arrayDays = array();
        $arrayDays["Monday"] 	= "Segunda-Feira";
        $arrayDays["Tuesday"] 	= "Terça-Feira";
        $arrayDays["Wednesday"] = "Quarta-Feira";
        $arrayDays["Thursday"] 	= "Quinta-Feira";
        $arrayDays["Friday"] 	= "Sexta-Feira";
        $arrayDays["Saturday"] 	= "Sabado";
        $arrayDays["Sunday"] 	= "Domingo";

        if(strtolower($lng)=="pt"){
            return $arrayDays[$day["weekday"]];
        } elseif(strtolower($lng)=="en") {
            return $day["weekday"];
        }
    }

    /**
     * Get the day of the week the date reported
     *
     * @param Integer $day
     * @param Integer $month
     * @param Integer $year
     * @param String $lng
     * @return String
     */
    public static function dayWeek($day,$month,$year,$lng = "pt"){ // Parameter can be pt or en
        $newDay 	= getdate(mktime(0,0,0,$month,$day,$year));
        $arrayDays 	= array();
        $arrayDays["Monday"]	= "Segunda-Feira";
        $arrayDays["Tuesday"] 	= "Terça-Feira";
        $arrayDays["Wednesday"] = "Quarta-Feira";
        $arrayDays["Thursday"] 	= "Quinta-Feira";
        $arrayDays["Friday"] 	= "Sexta-Feira";
        $arrayDays["Saturday"] 	= "Sabado";
        $arrayDays["Sunday"] 	= "Domingo";

        if(strtolower($lng)=="pt"){
            return $arrayDays[$newDay["weekday"]];
        } elseif(strtolower($lng)=="en") {
            return $newDay["weekday"];
        }
    }



    /**
     * Returns whether a date falls on a weekend.
     *
     * @param  int     $_date Unix timestamp of the date.
     * @return boolean
     */
    public static function isWeekend( $_date ) {
        return ( weekday( $_date ) == 0 || weekday( $_date ) == 6 );
    }

    /**
     * Returns a string representation of the date, of differing format
     * depending on how recent the date is.
     *
     * @param  int    $_date Unix timestamp of the date.
     * @return string        String representation of the date.
     */
    public static function niceDate( $_date ) {
        $date_ymd = date( "Ymd", $_date );
        $now = time();

        if ( $date_ymd == date( "Ymd", $now + 86400 ) ) { // tomorrow
            return "Tomorrow";
        } elseif ( $date_ymd == date( "Ymd", $now ) ) { // today
            return "Today";
        } elseif ( $date_ymd == date( "Ymd", $now - 86400 ) ) { // yesterday
            return "Yesterday";
        } elseif ( ( $now < $_date ) && ( abs( $now - $_date ) < 518400 ) ) { // next week
            return "Next ".date( "l", $_date );
        } elseif ( ( $now > $_date ) && ( abs( $now - $_date ) < 518400 ) ) { // previous week
            return "Last ".date( "l", $_date );
        } elseif ( date( "Y", $now ) == date( "Y", $_date ) ) { // this year
            return date( "j M", $_date );
        } else {
            return date( "j M Y", $_date );
        }
    }

    /**
     * Returns a string representation of the date and time, of differing format
     * depending on how recent the date is.
     *
     * @param  int    $_datetime Unix timestamp of the date.
     * @return string            String representation of the date and time.
     */
    public static function niceDatetime( $_datetime ) {
        $datetime_ymd = date( "Ymd", $_datetime );
        return nice_date( $_datetime ).", ".date( "g:ia", $_datetime );
    }


    ////////////////////////////////////////////////////////////////////////////////
    //                               FORM FUNCTIONS                               //
    ////////////////////////////////////////////////////////////////////////////////


    /**
     * Displays a <select> box. Uses the normal conventions, e.g. table names begin
     * with "tbl", key fields are "id" and identifier fields are "name".
     *
     * @param  string $_name       Name of the HTML select box.
     * @param  string $_table      Name of the table from which to get item data.
     * @param  int    $_id         ID of the item to be preselected.
     * @param  string $_where      'WHERE' clause to be used in the SQL query.
     * @param  string $_onChange   JavaScript to execute on change.
     * @param  string $_style      CSS attributes to apply.
     * @param  string $_zeroText   Text value for the zero option.
     * @param  string $_idField    Name of the field from which to get item IDs.
     * @param  string $_nameField  Name of the field from which to get item names.
     * @param  string $_orderBy    Name of the field by which to order items.
     * @param  string $_nameField2 Name of the field for additional name data.
     */
    public static function html_select( $_name, $_table, $_id=0, $_where="", $_onChange="", $_style="", $_zeroText="", $_idField="id", $_nameField="name", $_orderBy="name", $_nameField2="" ) {
        $query = "SELECT ".$_idField." AS id, ".$_nameField." AS name";

        if ( isset( $_nameField2 ) && !empty( $_nameField2 ) )
            $query .= ", CONCAT( ' ', ".$_nameField2." ) AS name2";

        $query .= " FROM ".addslashes( $_table );

        if ( isset( $_where ) && !empty( $_where ) )
            $query .= " WHERE ".$_where;

        $query .= " ORDER BY ".$_orderBy;

        $result = db_query( $query );

        print "<select name=\"".$_name."\"".( ( $_onChange != "" ) ? " onChange=\"".$_onChange."\"" : "" ).( ( $_style != "" ) ? " style=\"".$_style."\"" : "" ).">\n";
        print "<option value=\"0\">".$_zeroText."</option>\n";
        while ( $object = db_fetch_assoc( $result ) ) {
            print "<option value=\"".$object["id"]."\"".( ( $_id == $object["id"] ) ? " selected" : "" ).">".$object["name"];
            if ( array_key_exists( "name2", $object ) ) { print $object["name2"]; }
            print "</option>\n";
        }
        print "</select>\n";
    }

    /**
     * Maintains state.
     *
     * To use, create a global array called $stateVars which contains strings
     * representing the names of global variables you wish to pass around.
     *
     * Example of using GET-mode syntax:
     * <code>
     * print "example.php?".state( "GET" );
     * </code>
     *
     * Example of using POST-mode syntax:
     * <code>
     * print "<form action=\"example.php\" method=\"post\">";
     * print state( "POST" );
     * print "</form>";
     * </code>
     *
     * @see STATE_MODE_GET
     * @see STATE_MODE_POST
     * @param  string $_mode Either "GET" or "POST".
     * @param  string $_omit Comma-separated string of variables to omit.
     * @return string        String suitable for insertion into a URL (if $_mode is
     *                       "GET"), or hidden input fields (if $_mode is "POST").
     */
    public static function state( $_mode, $_omit="" ) {
        $_mode = strtoupper( $_mode );
        $return = "";

        if ( isset( $GLOBALS["stateVars"] ) && is_array( $GLOBALS["stateVars"] ) ) {
            foreach( $GLOBALS["stateVars"] as $var ) {
                if ( isset( $GLOBALS[$var] ) && !strstr( $_omit, $var ) ) {
                    if ( $_mode == self::state_mod_get) {
                        $return .= urlencode( $var )."=".urlencode( $GLOBALS[$var] )."&";
                    } else {
                        $return .= "<input type=\"hidden\" name=\"".$var."\" value=\"".$GLOBALS[$var]."\">\n";
                    }
                }
            }
        }

        return $return;
    }


    ////////////////////////////////////////////////////////////////////////////////
    //                               HTTP FUNCTIONS                               //
    ////////////////////////////////////////////////////////////////////////////////


    /**
     * Sends HTTP headers to redirect elsewhere, then exits the script.
     *
     * @param string $_target The URL to which the client should be redirected.
     */
    public static function redirect( $_target ) {
        if ( ob_get_length() )
            ob_end_clean();
        //header( "302 Moved Temporarily" );
        header( "Location: ".$_target );
        exit;
    }

    //* End of functions related to date *//

    // Bellow are the functions related with JavaScript

    /**
     * Alert
     *
     * @param String $msg
     */
    public static function alert($msg){
        echo "<script language='javascript'>
            <!--	
            alert('".$msg."');
        -->
            </script>";
    }

    /**
     * Alert and back to previous page
     *
     * @param String $msg
     */
    public static function alertBack($msg){
        echo "<script language='javascript'>
            <!--	
            alert('".$msg."');
        history.back();
        -->
            </script>";
    }

    /**
     * Back to the previous page
     *
     */
    public static function goBack(){
        echo "<script language='javascript'>
            <!--	
            history.back();
        -->
            </script>";
    }

    /**
     * Close actual window
     *
     */
    public static function closeWindow(){
        echo "<script language='javascript'>
            <!-- 
            window.close();
        -->
            </script>";
    }

    /**
     * Redirect page
     *
     * @param String $page
     */
    public static function jsRedirect($page){
        echo "<script language='javascript'>
            <!--	
            location.href='".$page."';
        -->
            </script>";
    }


    /**
     * Update current window
     *
     */
    public static function update(){
        echo "<script language='javascript'>
            <!--	
            window.location.reload();
        -->
            </script>";
    }

    //* End of javascript's functions *//

    // Bellow are the functions related with strings or arrays

    /**
     * Anti SQL Injection: Only lets through numbers and letters
     *
     * @param String $str
     * @return Boolean
     */
    public static function no_injection_login($str){
        if(!preg_match("/[^\sa-zA-Z0-9]/i", $str)){
            return true;
        } else {
            return false;
        }
    }

    /**
     * Validate CPF
     *
     * @param String $cpf
     * @return Boolean
     */
    public static function validateCpf($cpf){
        for( $i = 0; $i < 10; $i++ ){
            if ( $cpf ==  str_repeat( $i , 11) or !preg_match("@^[0-9]{11}$@", $cpf ) or $cpf == "12345678909" )
                return false;
            if ( $i < 9 ) $soma[]  = $cpf{$i} * ( 10 - $i );
            $soma2[] = $cpf{$i} * ( 11 - $i );
        }
        if(((array_sum($soma)% 11) < 2 ? 0 : 11 - ( array_sum($soma)  % 11 )) != $cpf{9})
            return false;
        return ((( array_sum($soma2)% 11 ) < 2 ? 0 : 11 - ( array_sum($soma2) % 11 )) != $cpf{10}) ? false : true;
    }

    /**
     * Validate Email
     *
     * @param String $address
     * @return unknown
     */
    public static function validateEmail($address) {
        if (function_exists('filter_var')) { //Introduced in PHP 5.2
            if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
                return false;
            } else {
                return true;
            }
        } else {
            return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
        }
    }

    /**
     * Rewirte String with accents
     *
     * @param String $str
     * @return String
     */
    public static function rewriteString($str){
        $listArr = array(
                "á"=>"&aacute;",
                "à"=>"&agrave;",
                "Á"=>"&Aacute;",
                "À"=>"&Agrave;",
                "ã"=>"&atilde;",
                "Ã"=>"&Atilde;",
                "â"=>"&acirc;",
                "Â"=>"&Acirc",

                "é"=>"&eacute;",
                "É"=>"&Eacute;",
                "ê"=>"&ecirc;",
                "Ê"=>"&Ecirc;",

                "í"=>"&iacute;",
                "Í"=>"&Iacute;",

                "ú"=>"&uacute;",
                "Ú"=>"&Uacute;",

                "ó"=>"&oacute;",
                "Ó"=>"&Oacute;",
                "õ"=>"&otilde;",

                "ç"=>"&ccedil;",
                "Ç"=>"&Ccedil;",

                "^"=>"&circ;",
                "~"=>"&tilde;",
                "´"=>"&acute;",
                "`"=>"&grave;",

                "ª"=>"&ordf;",
                "º"=>"&ordm;",
                "÷"=>"&divide;",
                "ü"=>"u",
                "©"=>"&reg;"
                    );
        return strtr($str,$listArr);
    }

    // Remove all the tags of string
    public static function removeTags($str){
        return preg_replace("/\<[^\>]*\>?/"," ",$str);
    }

    /**
     * Remove all the tags
     * Only de tag's name
     * Ex: leaveTags($str,'img','a')
     *
     * @return unknown
     */
    public static function leaveTags(){
        $args = func_get_args();
        $str = $args[0];
        if(is_array($args)){
            foreach($args as $arg){
                if($args[0]!=$arg){
                    $pattern = "/\<".$arg."[^\>]*\>?/";
                    $str = preg_replace($pattern," ",$str);
                }
            }
        }
        return $str;
    }

    /**
     * debugArray function use the print_r() function
     * and show html tag <pre></pre> to show correctly in your screen
     *
     * @param Array $array
     */
    public static function debugArray($array){
        echo "<pre>";
        echo "<code>";
        print_r($array);
        echo "</code>";
        echo "</pre>";
    }

    /**
     * Limit point from string given
     *
     * @param String $str
     * @param Integer $limit
     * @return unknown
     */
    public static function limitPoint($str,$limit=3){
        if(strpos($str,",")!==false){
            list($numero,$decimal) = explode(",",$str);
            if(strlen($decimal)>$limit){
                $decimal = substr($decimal,0,$limit);
            }
            return $numero.",".$decimal;
        } elseif(strpos($str,".")!==false) {
            list($numero,$decimal) = explode(".",$str);
            if(strlen($decimal)>$limit){
                $decimal = substr($decimal,0,$limit);
            }
            return $numero.".".$decimal;
        } else {
            return $str;
        }
    }

    /**
     * This function delete repeated data in the array
     *
     * @param Array $array
     * @return Array
     */
    public static function arrayDiffValue($array){
        if(is_array($array)){
            $numArray = count($array);
            $newArray = array();

            if($numArray>0){
                $newArray[0] = $array[0];
                $i=0;
                do {
                    foreach ($array AS $key=>$value){
                        if(!in_array($value,$newArray)){
                            $newArray[] = $value;
                        }
                        $i++;
                    }
                } while ($i<3);
                return $newArray;
            } else {
                // Empty array
                return false;
            }
        } else {
            // Not array
            return false;
        }
    }

    /**
     * This function bellow send data via post
     * The $packet parameter should be a array
     * I don't use this funcion many times, I only use in restricted situations
     *
     * @param String $url
     * @param Array $packet
     * @return Array
     */
    public static function execPage($url,$packet){
        $o="";
        foreach ($packet as $key=>$value){
            $o.= "$key=".utf8_encode($value)."&";
        }

        $args = substr($o,0,-1);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, 1 );
        curl_setopt($ch, CURLOPT_POSTFIELDS,$args);
        $result	   = curl_exec($ch);
        $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $result[0] = $result;
        $result[1] = $responseCode;
        return $result;
    }
	
	/**
	 * Get ip address.
	 *
	 * @return string
	 */
    public static function getIp() {
        if ($_SERVER["HTTP_X_FORWARDED_FOR"])
            $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        else if ($_SERVER["HTTP_CLIENT_IP"])
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        else if ($_SERVER["REMOTE_ADDR"])
            $ip = $_SERVER["REMOTE_ADDR"];
        else if (getenv("HTTP_X_FORWARDED_FOR"))
            $ip = getenv("HTTP_X_FORWARDED_FOR");
        else if (getenv("HTTP_CLIENT_IP"))
            $ip = getenv("HTTP_CLIENT_IP");
        else if (getenv("REMOTE_ADDR"))  
            $ip = getenv("REMOTE_ADDR");
        else
            $ip = "Unknown";
        return $ip;
    }

	/**
	 * Add days , month or year to an given date.
	 *
	 * @param string $date Target date.
	 * @param string $int Number of days or months or year.
	 * @param string $unit Day or Month or Year.
	 *
	 * @return date  Return a new date value.
	 */
    public static function dateAdd($date, $int, $unit = "d") {
        $dateArr = explode("-", $date);
        $value[$unit] = $int; //myokweb.cn
        return date("Y-m-d", mktime(0,0,0, $dateArr[1] + $value['m'], $dateArr[2] + $value['d'], $dateArr[0] + $value['y'])); //myokweb.cn
    } 

	/**
	 * Get all avaiable file types for web application.
	 *
	 * @return array(fileExt => fileType) Array contains all file extension and file types.
	 */
    public static function getAllFileTypes() {
        $mime_types = array(
                'gif' => 'image/gif', 'jpg' => 'image/jpeg',
                'jpeg' => 'image/jpeg',
                'jpe' => 'image/jpeg',
                'bmp' => 'image/bmp',
                'png' => 'image/png',
                'tif' => 'image/tiff', 
                'tiff' => 'image/tiff',
                'pict' => 'image/x-pict',
                'pic' => 'image/x-pict',
                'pct' => 'image/x-pict',
                'tif' => 'image/tiff',
                'tiff' => 'image/tiff',
                'psd' => 'image/x-photoshop',

                'swf' => 'application/x-shockwave-flash',
                'js' => 'application/x-javascrīpt',
                'pdf' => 'application/pdf',
                'ps' => 'application/postscrīpt',
                'eps' => 'application/postscrīpt',
                'ai' => 'application/postscrīpt',
                'wmf' => 'application/x-msmetafile',

                'css' => 'text/css',
                'htm' => 'text/html',
                'html' => 'text/html',
                'txt' => 'text/plain', 
                'xml' => 'text/xml',
                'wml' => 'text/wml',
                'wbmp' => 'image/vnd.wap.wbmp',

                'mid' => 'audio/midi',
                'wav' => 'audio/wav',
                'mp3' => 'audio/mpeg', 'mp2' => 'audio/mpeg',

                'avi' => 'video/x-msvideo',
                'mpeg' => 'video/mpeg',
                'mpg' => 'video/mpeg',
                'qt' => 'video/quicktime',
                'mov' => 'video/quicktime', 'lha' => 'application/x-lha',
                'lzh' => 'application/x-lha',
                'z' => 'application/x-compress',
                'gtar' => 'application/x-gtar',
                'gz' => 'application/x-gzip',
                'gzip' => 'application/x-gzip',
                'tgz' => 'application/x-gzip',
                'tar' => 'application/x-tar',
                'bz2' => 'application/bzip2',
                'zip' => 'application/zip',
                'arj' => 'application/x-arj',
                'rar' => 'application/x-rar-compressed',

                'hqx' => 'application/mac-binhex40',
                'sit' => 'application/x-stuffit',
                'bin' => 'application/x-macbinary',

                'uu' => 'text/x-uuencode',
                'uue' => 'text/x-uuencode',

                'latex'=> 'application/x-latex',
                'ltx' => 'application/x-latex',
                'tcl' => 'application/x-tcl',

                'pgp' => 'application/pgp',
                'asc' => 'application/pgp',
                'exe' => 'application/x-msdownload',
                'doc' => 'application/msword', 'rtf' => 'application/rtf',
                'xls' => 'application/vnd.ms-excel',
                'ppt' => 'application/vnd.ms-powerpoint',
                'mdb' => 'application/x-msaccess',
                'wri' => 'application/x-mswrite',
                ); 
        return $mime_types;
    } 

	/**
	 * Check if the email is an valid email address.
	 *
	 * @param string $inAddress Input email address.
	 * @return bool  If the email is valid then return true otherwise return false.
	 */
    public static function checkEmail($inAddress)
    {
        return (ereg("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$",$inAddress));
    } 

	/**
	 * Encrypt an given string with to store in database in an safe manner. Also can be used for general encryption.
	 *
	 * @param string $string String needed to be encrypted. 
	 * @param string $key Key to encrypt string.
	 *
	 * @return string Encrypted string.
	 */
    public static function encrypt($string, $key = 'key') {
        return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
    }

	/**
	 * Decrypt an encrypted string with key.
	 *
	 * @param string $encrypted Encrypted string.
	 * @param string $key Key to decrypted string
	 *
	 * @return string Original string.
	 */
    public static function decrypt($encrypted, $key='key') {
        return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
    }

	/**
	 * Format an given number and display as currency.
	 *
	 * @param string $num 
	 *
	 * @return string Formatted currency format.
	 */
    public static function formatNumber($num, $n = 0){
        return number_format($num, $n, ".", ",");
    }

   	/**
   	 * Format text convert \r into <br />, etc
   	 *
   	 * @param string $string Input string needed to be manipulated.
   	 * @return string Output string which has been formatted.
   	 */
 	public static function formatString($string = ""){
        $string = preg_replace(array("/ /", "/　/"), array("&nbsp;", "&nbsp;&nbsp;"), $string);
        return nl2br($string);
    }

	/**
	 * Format an given text to remove special character.
	 *
	 * @param string $text Input text vlaue.
	 * @return string Output text.
	 */
    function formatContent($text){
        $trans = get_html_translation_table(HTML_SPECIALCHARS);
        $trans = array_flip($trans);
        $text = strtr($text, $trans);
        //$text = str_replace("\n", "<br>", $text);
        //$text = str_replace(" ", "&nbsp;", $text);
        return $text;
    }

    public static function browserInfo()
    {
        $browser="";
		$browserver="";  
        $Browsers =array("Lynx","MOSAIC","AOL","Opera","JAVA","MacWeb","WebExplorer","OmniWeb");
        $Agent = $_SERVER["HTTP_USER_AGENT"];
        for ($i=0; $i<=7; $i++)  
        {
            if (strpos($Agent,$Browsers[$i]))
            {
                $browser = $Browsers[$i];
                $browserver ="";
            }
        }
        if (ereg("Mozilla",$Agent) && !ereg("MSIE",$Agent))  
        {
            $temp =explode("(", $Agent); $Part=$temp[0];
            $temp =explode("/", $Part); $browserver=$temp[1];
            $temp =explode(" ",$browserver); $browserver=$temp[0];
            $browserver =preg_replace("/([d.]+)/","1",$browserver);
            $browserver = " $browserver";  
            $browser = "Netscape Navigator";
        }
        if (ereg("Mozilla",$Agent) && ereg("Opera",$Agent))
        {
            $temp =explode("(", $Agent); $Part=$temp[1];
            $temp =explode(")", $Part); $browserver=$temp[1];
            $temp =explode(" ",$browserver);$browserver=$temp[2];
            $browserver =preg_replace("/([d.]+)/","1",$browserver);
            $browserver = " $browserver";
            $browser = "Opera";
        }
        if (ereg("Mozilla",$Agent) && ereg("MSIE",$Agent))  
        {
            $temp = explode("(", $Agent); $Part=$temp[1];
            $temp = explode(";",$Part); $Part=$temp[1];  
            $temp = explode(" ",$Part);$browserver=$temp[2];
            $browserver =preg_replace("/([d.]+)/","1",$browserver);
            $browserver = " $browserver";
            $browser = "Internet Explorer";
        }
        if ($browser!="")
        {
            $browseinfo = "$browser$browserver";
        }
        else
        {
            $browseinfo = "Unknown";
        }
        return $browseinfo;
    } 
	
	/**
	 * Get os information.
	 *
	 * @return string Operational system info.
	 */
    public static function osInfo() {
        $os="";
        $Agent = $_SERVER["HTTP_USER_AGENT"];
		var_dump($Agent);
        if (eregi('win',$Agent) && strpos($Agent, '95')) {  
            $os="Windows 95";
        }
        elseif (eregi('win 9x',$Agent) && strpos($Agent, '4.90')) {
            $os="Windows ME";
        }
        elseif (eregi('win',$Agent) && ereg('98',$Agent)) {
            $os="Windows 98";
        }
        elseif (eregi('win',$Agent) && eregi('nt 5.0',$Agent)) {
            $os="Windows 2000";
        }
        elseif (eregi('win',$Agent) && eregi('nt',$Agent)) {  
            $os="Windows NT";
        }
        elseif (eregi('win',$Agent) && eregi('nt 5.1',$Agent)) {
            $os="Windows XP";
        }
        elseif (eregi('win',$Agent) && ereg('32',$Agent)) {
            $os="Windows 32";
        }
        elseif (eregi('linux',$Agent)) {
            $os="Linux";
        }
        elseif (eregi('unix',$Agent)) {
            $os="Unix";  
        }
        elseif (eregi('sun',$Agent) && eregi('os',$Agent)) {
            $os="SunOS";
        }
        elseif (eregi('ibm',$Agent) && eregi('os',$Agent)) {  
            $os="IBM OS/2";
        }
        elseif (eregi('Macintosh',$Agent)) {
            $os="Macintosh";
        }
        elseif (eregi('PowerPC',$Agent)) {
            $os="PowerPC";
        }
        elseif (eregi('AIX',$Agent)) {
            $os="AIX";
        }
        elseif (eregi('HPUX',$Agent)) {
            $os="HPUX";
        }
        elseif (eregi('NetBSD',$Agent)) {
            $os="NetBSD";
        }
        elseif (eregi('BSD',$Agent)) {
            $os="BSD";
        }
        elseif (ereg('OSF1',$Agent)) {  
            $os="OSF1";
        }
        elseif (ereg('IRIX',$Agent)) {
            $os="IRIX";
        }
        elseif (eregi('FreeBSD',$Agent)) {
            $os="FreeBSD";
        }
        if ($os=='') $os = "Unknown";

        return $os;
    }

	/**
	 * Read from file.
	 *
	 * @param string $file_name File path.
	 */
    public static function readFromFile($file_name) {
        if (file_exists($file_name)) {
            $filenum=fopen($file_name,"r");
            flock($filenum,LOCK_EX);
            $file_data=fread($filenum, filesize($file_name));
            rewind($filenum);
            fclose($filenum);
            return $file_data;
        }
    } 

    public static function writeToFile($file_name,$data,$method="w") {
        $filenum=fopen($file_name,$method);
        flock($filenum,LOCK_EX);
        $file_data=fwrite($filenum,$data);
        fclose($filenum);
        return $file_data;
    } 

    public static function relativeToAbsolutePath($content, $feed_url) {  
        preg_match('/(http|https|ftp):///', $feed_url, $protocol);  
            $server_url = preg_replace("/(http|https|ftp|news):///", "", $feed_url);  
                $server_url = preg_replace("//.*/", "", $server_url);  

                 if ($server_url == '') {  
                     return $content;  
                 }  

                 if (isset($protocol[0])) {  
                     $new_content = preg_replace('/href="//', 'href="'.$protocol[0].$server_url.'/', $content);  
                     $new_content = preg_replace('/src="//', 'src="'.$protocol[0].$server_url.'/', $new_content);  
                 } else {  
                     $new_content = $content;  
                 }  
                 return $new_content;  
    }  

	/**
	 * Convert an bit size to display in different format.
	 *
	 * @param string $num 
	 * @return string Ouput bit size in different format.
	 */
    public static function bitsize($num){
        if(!preg_match("/^[0-9]+$/", $num)) return 0;
        $type = array( "B", "KB", "MB", "GB", "TB", "PB" );

        $j = 0;
        while( $num >= 1024 ) {
            if( $j >= 5 ) return $num.$type[$j];
            $num = $num / 1024;
            $j++;
        }
        return $num.$type[$j];
    }

    public static function makedir( $dir, $mode = "0777" ) {
        if( ! $dir ) return 0;
        $dir = str_replace( "\\", "/", $dir );

        $mdir = "";
        foreach( explode( "/", $dir ) as $val ) {
            $mdir .= $val."/";
            if( $val == ".." || $val == "." ) continue;

            if( ! file_exists( $mdir ) ) {
                if(!@mkdir( $mdir, $mode )){
                    echo "Fail create [".$mdir."].";
                    exit;
                }
            }
        }
        return true;
    }

    /**
     * Add slashes to avoid sql injection.
     *
     * @param string $array Array contains input value as $key => $value pair.
	 *
     * @return array Output array contains values which has been already add slashes.
     */
    public static function addSS($array){
        foreach($array as $key=>$value){
            if(!is_array($value)){
                $array[$key]=trim(addslashes($value));
            }else{
                $this->add_s($array[$key]);
            }
        }

        return $array;
    }

    public static function specialhtml($array){
        if(is_array($array)){
            foreach($array as $key=>$value){
                if(!is_array($value)){
                    $array[$key]=htmlspecialchars($value);
                }else{
                    $this->specialhtml($array[$key]);
                }
            }
        }else{
            $array = htmlspecialchars($array);
        }

        return $array;
    }

    
    public static function aweek($gdate = "", $first = 0){
        if(!$gdate) $gdate = date("Y-m-d");
        $w = date("w", strtotime($gdate));
        $dn = $w ? $w - $first : 6;
        $st = date("Y-m-d", strtotime("$gdate -".$dn." days"));
        $en = date("Y-m-d", strtotime("$st +6 days"));
        return array($st, $en);
    }

    /**
     * Get date in RFC3339
     * For example used in XML/Atom
     *
     * @param integer $timestamp
     * @return string date in RFC3339
     * @author Boris Korobkov
     * @see http://tools.ietf.org/html/rfc3339
     */
    public static function date3339($timestamp=0) {

        if (!$timestamp) {
            $timestamp = time();
        }
        $date = date('Y-m-d\TH:i:s', $timestamp);

        $matches = array();
        if (preg_match('/^([\-+])(\d{2})(\d{2})$/', date('O', $timestamp), $matches)) {
            $date .= $matches[1].$matches[2].':'.$matches[3];
        } else {
            $date .= 'Z';
        }
        return $date;

    }

	////////////////////////////////////////////////////////////////////////////////
    //                                  Datebase related utils                    //
    ////////////////////////////////////////////////////////////////////////////////

	public static function queryGeneralDataStorageByKey($key) {
			
	}
	
    /**
     * Get the admin settings row in the table by an given key. 
     * 
     * @param string $key Key matchese the field in table.
     * @static
     * @access public
     * @return array Array contains values for field and value in database table.
     */
	public static function getAdminSettingByKey($key) {
		$pdo 	= SingletonPdo::getInstance();
		$query 	= sprintf("SELECT * FROM admin_settings WHERE `field` = '%s'", $key);
		$result = $pdo->fetchRow($query);
		return $result[0];
	}

    /**
     * function getByPk generic function to get an row based on given id and table name.
     * 
     * @param string $tableName Name of table needed to be quried .
     * @param string|int $pk PK of record needed to be retrieved.
     * @param string Default PK set to string id. 
     * @static
     * @access public
     * @return array Array contains only one row as result.
     */
    public static function getByPk($tableName, $pkValue, $pk = 'id') {
        $pdo = SingletonPdo::getInstance();
        $query = sprintf("SELECT * FROM `%s` WHERE `%s` = '%s'", $tableName, $pk, $pkValue);
        $result = $pdo->fetchRow($query, $pdo::FETCH_ASSOC);
        return $result[0];
    }

	/**
	 * Update or insert a new value to admin_settings table.
	 *
	 * @param string $key Key in table.
	 * @param string $value Value for the key.
	 *
	 * @return void
	 */
	public static function insertOrUpdateAdminSetting($key = '', $value = '') {
		if($key !== '' and $value !== '') {
			$pdo 	= SingletonPdo::getInstance();
			$query 	= sprintf("SELECT COUNT(*) AS total FROM admin_settings WHERE  `field` = '%s'", $key);
			$result = $pdo->fetchRow($query);
			if($result[0]['total'] == 0) {
				//do insert
				$query 	= sprintf("INSERT INTO admin_settings (`field`,`value`) VALUES ('%s', '%s')", $key, $value);
				return $pdo->simpleQuery($query);
			} else if($result[0]['total'] == 1) {
				//do update
				$query 	= sprintf("UPDATE admin_settings SET `value` = '%s' WHERE `field` = '%s' ", $value, $key);
				return $pdo->simpleQuery($query);
			}
		}

		return false;
	}

    /**
     * Function getUrl used to get base url or get current page url.
     * 
     * @param string $option Set to base or page
     * @static
     * @access public
     *
     * @return string Full string contains url.
     */
    public static function getUrl($option = 'base') {
        $pageURL = 'http';
        if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
        $pageURL .= "://";
        if($option == 'base') { 
            if ($_SERVER["SERVER_PORT"] != "80") {
                $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"];
            } else {
                $pageURL .= $_SERVER["SERVER_NAME"];
            }
        } else if($option == 'page') {
            if ($_SERVER["SERVER_PORT"] != "80") {
                $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
            } else {
                $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
            }
        } else {
            return false;
        }
        return $pageURL;
    }

     
    /**
     * Get initials for names. 
     *
     * @param Full name .
     * @static
     * @access public
     *
     * @return string initials for given name.
     */
    public static function initials($name){ 
        $nword = explode(" ",$name); 
        foreach($nword as $letter){ 
            $new_name .= $letter{0}.' '; 
        } 
        return strtoupper($new_name); 
    } 
    
    /**
     * function checkAvaiable check if an given value is set and is not blank.
     * 
     * @param mixed $value Given value, could be any type.
     * @static
     * @access public
     *
     * @return bool If the value is avaiable then return true, otherwise return false.
     */
    public static function checkAvaiable($value) {
        if($value != NULL and trim($value) != '') {
            return true;
        }

        return false;
    }

    /**
     * Function array_sort_by_column sort an array by column.
     * 
     * @param array $arr Input array.
     * @param string $col Array column.
     * @param string $dir Sorting direction.
     * @static
     * @access public
     * @return array Return the sorted array.
     */
    public static function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
        $sort_col = array();
        foreach ($arr as $key=> $row) {
            $sort_col[$key] = $row[$col];
        }

        array_multisort($sort_col, $dir, $arr);
    }

	/**
	 * Function getFinancialYearDropDown generate an drop down list base on $_GET variables.
	 * 
	 * @param array $getArray Most likely this value will be passed as $_GET.
	 * @param string $yearKey Key store in getArray to indicate the finacial year value in the array. 
	 * @param int $yearsBackward Indicate how many year should be displayed count backward.
	 * @param int $yearsForward  Indicate how many year should be displayed count forward.
	 * @static
	 * @access public
	 *
	 * @return string Html select element contains all financial years. 
	 */
	public static function getFinancialYearDropDown($getArray, $yearKey = 'year', $yearsBackward = 3, $yearsForward = 2) {
		$currentYear = self::getFinancialYear((int)date('Y'), (int)date('m'));
		$currentSelectedYear = isset($getArray[$yearKey]) ? $getArray[$yearKey] : $currentYear;
		$html = '<select id="'.$yearKey.'" name="'.$yearKey.'">';		
		for($i = $currentYear - $yearsBackward; $i <= $currentYear + $yearsForward; $i++) {
			$selected = $i == $currentSelectedYear ? ' SELECTED ' : '';
			$html .= '<option '.$selected.' value="'.$i.'">'.$i.'</option>';	
		}
		
		$html .= '</select>';

		return $html;
	}

    /**
     * Function isDBTableFieldComparable query an database table and fields see if one specific field is compareable or not.
     * 
     * @param string $tableName Name of db table.
     * @param string $field Name of field.
     * @static
     * @access public
     * @return bool  Return true if the field is compareable, otherwise return false.
     */
    public static function isDBTableFieldComparable($tableName, $field) {
        $pdo      = SingletonPdo::getInstance(); 
        $describe = $pdo->fetchRow(sprintf("SHOW COLUMNS FROM `%s` WHERE Field = '%s'",$tableName ,$field));    
        if(count($describe) == 0) {
            return false;
        }
        $type     = $describe[0]['Type'];

        if(self::findStrInStr($type, 'int') or self::findStrInStr($type, 'bigint') or self::findStrInStr($type, 'float') or self::findStrInStr($type, 'double') or self::findStrInStr($type, 'decimal') or self::findStrInStr($type, 'date')) {
            return true;
        } 

        return false;
    }

    /**
     * Function findStrInStr see if an string contains an other string.
     * 
     * @param string $myString Target string.
     * @param string $findMe   String needed to be founded. 
     * @static
     * @access public
     * @return bool
     */
    public static function findStrInStr($myString, $findMe) {
        $pos = strpos($myString, $findMe);
        if ($pos !== false) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Function isAjaxRequest used to determin if in-comming request is an ajax request or not.
     * 
     * @static
     * @access public
     * @return bool
     */
    public static function isAjaxRequest() {
        return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'));
    }

    /**
     * Function cutString Cut a long string in to short displaying format, for instance string "I am a dog and I eat meat" need
     * to be displayed, it will cut in to "I am a dog.....", for saving spaces displaying purpose.
     *
     * @param string $text Input text.
     * @param int $maxchar Max character displayed.
     * @param string $end Ending string. 
     * @static
     * @access public
     * @return string Formatted string to be displayed.
     */
    public static function cutString($text,$maxchar,$end='...'){
        if(strlen($text)>$maxchar){
            $words=explode(" ",$text);
            $output = '';
            $i=0;
            while(1){
                $length = (strlen($output)+strlen($words[$i]));
                if($length>$maxchar){
                    break;
                }else{
                    $output = $output." ".$words[$i];
                    ++$i;
                };
            };
        }else{
            $output = $text;
        }

        if(strlen($text) < $maxchar) {
            return $text;
        }
        return $output.$end;
    }

    /**
     * dropDownFromDB generate drop down list from database. 
     * 
     * @param mixed $query 
     * @param mixed $inputArray 
     * @param array $inputOptions 
     * @static
     * @access public
     * @return void
     */
    public static function dropDownFromDB($query, $inputArray ,$inputOptions = array()) {
        if(count($inputOptions) == 0) return false;
        $pdo 	= SingletonPdo::getInstance();
        $html = '<select id="'.$inputOptions['id'].'" name="'.$inputOptions['id'].'"> ';
        
		$result = $pdo->fetchRow($query, PDO::FETCH_ASSOC);
		$currentSelected = isset($inputArray[$inputOptions['id']]) ? $inputArray[$inputOptions['id']] : '';

        if(isset($inputOptions['default']) and count($inputOptions['default']) == 2) {
            $selected = $inputOptions['default']['value'] == $currentSelected ? 'selected' : '';
            $html .= '<option '.$selected.' value="'.$inputOptions['default']['value'].'">'.$inputOptions['default']['display'].'</value>';
        }

        foreach($result as $k => $v) {
            $selected = $v['selectkey'] == $currentSelected ? 'selected' : '';
            if(isset($inputOptions['mapping']) and is_array($inputOptions['mapping'])) {
                $html .= '<option '.$selected.' value="'.$v['selectkey'].'">'.$inputOptions['mapping'][$v['selectkey']].'</option>';
            } else {
                $html .= '<option '.$selected.' value="'.$v['selectkey'].'">'.$v['selectkey'].'</option>';
            }
        }

        $html .= '</select>';
        return $html;
    }
    
    /**
     * getMonthNumberByName get month number by month name, for instance Jan matches 1, Feb matches 2, Mar matches 3,..etc.
     * 
     * @param string $month_name String as month name, such as Jan, Feb, Mar, Aug, May,.....
     * @static
     * @access public
     * @return void
     */
    public static function getMonthNumberByName($month_name) {
        for($i=1;$i<=12;$i++){
            if(strtolower(date("M", mktime(0, 0, 0, $i, 1, 0))) == strtolower($month_name)){
                return $i;
            }
        }
    }

    public static function CSVExport($query,$title = '', $fileName = 'data') {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        $output = '';

        if($title != '') $output .= $title. "\"\n";
        if(is_string($query)) {
            //if the query is string, then do an mysql query, 
            $pdo     = SingletonPdo::getInstance();
            $results = $pdo->fetchRow($query, $pdo::FETCH_ASSOC);
            $headerArr = array();
            foreach($header as $k => $v) {
                $headerArr[] = $k;
            }

            $output .= '"' . stripslashes(implode('","',$headerArr)) . "\"\n";

            foreach ($results as $result) {
                $tempArr = array();
                foreach($header as $key => $value) {
                    $tempArr[] = $result[$key];
                }

                $output .= '"' . stripslashes(implode('","',$tempArr)) . "\"\n";
            }
        } else if(is_array($query)) {
            //if the query is array, then the array will be data, just display directly
            foreach($query as $key => $value) {
                $output .= '"';
                $output .= stripslashes(implode('","', $value));
                $output .= "\"\n";
            }
        }

        header("Content-Length: ".strlen($output)); 
        header("Content-Disposition: attachment; filename=".$fileName.".csv");
        echo $output;
        exit;
    }

    public static function getFileExtension($fileName) {
        return substr(strrchr($fileName,'.'),1);    
    }
}
